
#include "putsDispose.h"

void trainTransfilePuts(int fd,int sockfd,long sfilesize){
    lseek(fd,sfilesize,SEEK_SET);
    Train train;
    char buff[1024] = {0};
    while(1){
        bzero(buff,sizeof(buff));
        int rret = read(fd,buff,sizeof(buff));
        if(rret == 0){
            train.length = 0;
            send(sockfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);
            break;
        }
        train.length = rret;
        memcpy(train.data,buff,rret);
        send(sockfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);
    }
       

    return ;
}



void mmapTransfilePuts(int fd,int sockfd,long sfilesize,long cfilesize){
    ftruncate(fd,cfilesize);
    char * p = (char *)mmap(NULL,cfilesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    send(sockfd,p+sfilesize,cfilesize-sfilesize,MSG_NOSIGNAL);
    munmap(p,cfilesize-sfilesize);
     
     
    return ;
}


int putsDispose(int sockfd,char * cpath ,char * spath,char * username){    // -1 代表失败，0 代表 成功，

    /* printf("cpath:%s\n",cpath); */
    /* printf("spath:%s\n",spath); */

  
    int ret = access(cpath,F_OK);    //判断一下本地有没有这个文件
    if(ret != 0){
        printf("文件或目录不存在\n");
        return -1;                   //没有返回-1
    }
    DIR * dir = opendir(cpath);    //有的话检测一下是不是目录 
    if(dir != NULL ){
        printf("无法上传目录文件!\n");
        return -1;
    }
 
    
    char command[] = "puts";
    
    Train train;
    train.length = strlen(command);            //向后台发送puts信号
    memcpy(train.data,command,train.length);
    send(sockfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);
       
    int epollfd = epoll_create(1);         //创建监听
    addEpollNode(epollfd,sockfd);
    struct epoll_event readyset[1024];
    
    epoll_wait(epollfd,readyset,1024,-1);
    
    char * JWT;
    recvT(readyset[0].data.fd,&JWT);
    char * ip;
    recvT(readyset[0].data.fd,&ip);
    char * port;
    recvT(readyset[0].data.fd,&port);
    printf("JWT:%s\n",JWT);
    printf("ip:%s\n",ip);
    printf("port:%s\n",port);
    
    sockfd = createSockfd(ip,port);
    /* printf("建立链接\n"); */
    sendT(sockfd,JWT);
    
    addEpollNode(epollfd,sockfd);
    epoll_wait(epollfd,readyset,5,-1);
    
    char msg;
    recv(readyset[0].data.fd,&msg,1,MSG_NOSIGNAL);
    if(msg == '0'){
        printf("\n传输失败！\n");
        free(JWT);
        free(ip);
        free(port);
        return 0;
    }
    
    sendT(sockfd,command);
    sendT(sockfd,username);

    train.length = strlen(spath);         //发送服务器该传输的位置(父文件路径)
    memcpy(train.data,spath,train.length);
    send(sockfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);

   

    epoll_wait(epollfd,readyset,1024,-1);
    
    char path_true;
    recv(sockfd,&path_true,1,MSG_WAITALL);
    if(path_true == '2'){
        printf("\n服务端非目录文件！\n");
        free(JWT);
        free(ip);
        free(port);
        return 0;
    }
    if(path_true == '0'){
        printf("\n不存在该路径！\n");
        free(JWT);
        free(ip);
        free(port);
        return 0;
    }


    int length = strlen(cpath);    
    int i = length - 1;
    while(i>=0){                    //从路径中割出文件名
        if(cpath[i] == '/'){
            break;
        } 
        --i;
    }
    char docu_name[128] = {0};
    if(i == -1){        //防止cpath直接是 文件名
        strcpy(docu_name,cpath); 
    }else{
        for(int j = i+1 , k = 0; j < strlen(cpath) ; ++j , ++k){
            docu_name[k] = cpath[j];
        }
    }
    /* printf("name:%s\n",docu_name); */
    train.length = strlen(docu_name);            //发送文件名字
    memcpy(train.data,docu_name,train.length);
    send(sockfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);
    

    int fd = open(cpath,O_RDWR,0666);                 // 打开文件
    

    MD5_CTX ctx;                                  //计算文件md5值
    MD5_Init(&ctx);
    char buff[4096];
    while(1){
        bzero(buff,sizeof(buff));
        ssize_t rret = read(fd,buff,sizeof(buff));
        if(rret == 0){
            break;
        }              
        MD5_Update(&ctx,buff,rret);
    }
    unsigned char md[16];
    MD5_Final(md,&ctx);
    char md5_str_c[33] = {0};
    char num[3] = {0};
    for(int k =0 ; k < 16 ; ++k){
        sprintf(num,"%02x",md[k]);
        strcat(md5_str_c,num);
    }

    /* printf("客户端MD5为:%s\n",md5_str_c); */
    train.length = strlen(md5_str_c);              //发送md5值
    memcpy(train.data,md5_str_c,train.length);
    send(sockfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);
    

    epoll_wait(epollfd,readyset,1024,-1);

    char md5_has ;
    recv(readyset[0].data.fd,&md5_has,1,MSG_WAITALL);
    if(md5_has == '1'){
        printf("\n秒传成功！\n");
        free(JWT);
        free(ip);
        free(port);
        return 0;
    }




    struct stat statbuf;
    fstat(fd,&statbuf);
    /* printf("size:%ld\n",statbuf.st_size); */
    train.length = sizeof(statbuf.st_size);             //发送文件大小
    memcpy(train.data ,&statbuf.st_size,train.length);
    send(sockfd,&train,sizeof(train.length)+ train.length ,MSG_NOSIGNAL);
    

    char isBig;
    if(statbuf.st_size < 1073741824){
        isBig = '0';
    }else{
        isBig = '1';
    }
    send(sockfd,&isBig,1,MSG_NOSIGNAL);             //发送是不是大文件

    epoll_wait(epollfd,readyset,1024,-1);


    char has;                                   //接收服务器是否“有”信号
    recv(readyset[0].data.fd,&has,1,MSG_WAITALL);
    /* printf("接收has:%c\n",has); */
    if(has == '2'){
        printf("错误！存在同名目录\n");
        return 0;
    }
    if(has == '0'){
        if(isBig == '1'){
            mmapTransfilePuts(fd,sockfd,0,statbuf.st_size);
        }
        if(isBig == '0'){
            trainTransfilePuts(fd,sockfd,0);
        }
        return 0;
    }
    if(has == '1'){
        long sfilesize = 0;                //接收服务器文件长度
        recv(readyset[0].data.fd,&train.length,sizeof(train.length),MSG_WAITALL);
        recv(readyset[0].data.fd,train.data,train.length,MSG_WAITALL);
        memcpy(&sfilesize,train.data,train.length);

        char md5_str_s[64];      //接收服务器文件md5
        recv(readyset[0].data.fd,&train.length,sizeof(train.length),MSG_WAITALL);
        recv(readyset[0].data.fd,train.data,train.length,MSG_WAITALL);
        memcpy(md5_str_s,train.data,train.length);
        /* printf("收到server filesize:%ld\n",sfilesize); */
        /* printf("收到server md5:%s\n",md5_str_s); */
        lseek(fd,0,SEEK_SET);
        if(statbuf.st_size >= sfilesize){        //客户机文件长度大于服务器文件长度

            MD5_CTX ctx;
            MD5_Init(&ctx);
            char buff[4096];
            ssize_t readedsize = 0;
            ssize_t remainsize = 0;
            while(1){
                remainsize = sfilesize - readedsize;
                if(remainsize > sizeof(buff) ){
                    bzero(buff,sizeof(buff));
                    ssize_t rret = read(fd,buff,sizeof(buff));
                    readedsize =  readedsize + rret;
                    MD5_Update(&ctx,buff,rret);
                }else{
                    bzero(buff,sizeof(buff));
                    ssize_t rret = read(fd,buff,remainsize);
                    MD5_Update(&ctx,buff,rret);
                    break;
                }
            }
            unsigned char md[16];
            MD5_Final(md,&ctx);
            char md5_str_c[33] = {0};
            char num[3] = {0};
            for(int k =0 ; k < 16 ; ++k){
                sprintf(num,"%02x",md[k]);
                strcat(md5_str_c,num);
            }
            /* printf("客户机的md5:%s\n",md5_str_c); */

            if(strcmp(md5_str_c,md5_str_s)==0){
                send(sockfd,"1",2,MSG_NOSIGNAL);    //断点续传
                if(isBig == '1'){
                    mmapTransfilePuts(fd,sockfd,sfilesize,statbuf.st_size);
                }
                if(isBig == '0'){
                    trainTransfilePuts(fd,sockfd,sfilesize);
                }
            }else{
                send(sockfd,"0",2,MSG_NOSIGNAL);   //重传
                if(isBig == '1'){
                    mmapTransfilePuts(fd,sockfd,0,statbuf.st_size);
                }
                if(isBig == '0'){
                    trainTransfilePuts(fd,sockfd,0);
                }
            }
        }else{
            send(sockfd,"0",2,MSG_NOSIGNAL);
            if(isBig == '1'){
                mmapTransfilePuts(fd,sockfd,0,statbuf.st_size);
            }
            if(isBig == '0'){
                trainTransfilePuts(fd,sockfd,0);
            }
        }        
    }


    return 0;
}


